home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 …ember: Reference Library / Dev.CD Dec 00 RL Disk 1.toast / pc / technical documentation / develop / develop issue 27 / develop issue 27 code / internet config assistant / toolkit / tapplication.cp < prev    next >
Encoding:
Text File  |  1996-06-30  |  17.5 KB  |  772 lines

  1. /*
  2.   File:            TApplication.cp
  3.  
  4.   Contains:        TApplication: a class for applications with no document
  5.  
  6.   Written by:    Arno Gourdol
  7.  
  8.   Copyright:    © 1993-1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.  
  11. */
  12.  
  13.  
  14. #include "TApplication.h"
  15.  
  16. #include <ToolUtils.h>
  17. #include <Dialogs.h>
  18. #include <Devices.h>
  19. #include <Menus.h>
  20. #include <Gestalt.h>
  21. #include <Scrap.h>
  22. #include <QDOffscreen.h>
  23. #include <LowMem.h>
  24. #include <DiskInit.h>
  25. #include <SegLoad.h>                            // For ExitToShell
  26. #include <TextEdit.h>
  27. #include <Processes.h>
  28.  
  29. #include "assert.h"
  30. #include "macros.h"
  31.  
  32. //
  33. // Menu resources
  34. //
  35. enum
  36. {
  37.     kMainMenuBar = 128,                // Menu bar of the application
  38.     kAppleMenu = 128,                // Apple menu
  39.     kAboutMenuItem = 1,
  40.  
  41.     kFileMenu = 129,                // File menu
  42.     kCloseMenuItem = 1,
  43.     kQuitMenuItem = 3,
  44.  
  45.     kEditMenu = 130,                // Edit menu
  46.     kUndoMenuItem = 1,
  47.     kCutMenuItem = 3,
  48.     kCopyMenuItem = 4,
  49.     kPasteMenuItem = 5,
  50.     kClearMenuItem = 6
  51. };
  52.  
  53. //
  54. // Window, dialogs resources
  55. //
  56. enum
  57. {
  58.     kAboutBoxDialog = 128            // Resource ID for About box alert
  59. };
  60.  
  61. //
  62. // Result of GetScrapContent
  63. //
  64. #define kScrapHasText (1<<0)
  65. #define kScrapHasPict (1<<1)
  66. #define kScrapHasSound (1<<2)
  67. #define kScrapHasMovie (1<<3)
  68. #define kScrapHasUnknown (1<<8)
  69.  
  70. /*    Each item in the scrap begins with a resource type and length, followed
  71.   by some variable-length data. This data structure is used to parse
  72.   the scrap items. */
  73.  
  74. typedef struct
  75. {
  76.     ResType scrapType;
  77.     long scrapLength;
  78.     char scrapData[2];
  79. } ScrapItem, * ScrapItemPtr;
  80.  
  81.  
  82. // Template for the 'WIND' resource ??? Not used
  83. typedef struct
  84. {                                                
  85.     Rect boundsRect;
  86.     short procID;
  87.     short visible;
  88.     short goAwayFlag;
  89.     long refCon;
  90.     char title[2];
  91. } WindowTemplate, *WindowTemplatePtr, **WindowTemplateHandle;
  92.  
  93.  
  94. TApplication* TApplication::gApplication = NULL;            // The running application
  95.  
  96. unsigned long GetScrapContent(void);            // Returns the content of the scrap (PICT, TEXT...)
  97.  
  98.  
  99.  
  100. // --------------------------------------------------------------------
  101. // IdleProc
  102. // --------------------------------------------------------------------
  103. // Callback idle function
  104.  
  105. pascal Boolean TApplication::IdleProc(EventRecord *event, 
  106.                                         long *sleep, 
  107.                                         RgnHandle *mouseRgn)
  108. {
  109.     *mouseRgn = NULL;
  110.     
  111.     switch (event->what)
  112.     {
  113.         case nullEvent:
  114.             *sleep = 0;
  115.             break;
  116.             
  117.         case updateEvt:
  118.             {
  119.                 WindowRef window = (WindowRef)event->message;
  120.                 CWindow* windowObject = CWindow::GetCWindow(window);
  121.                 if (windowObject != NULL)
  122.                 {
  123.                     SetPort(windowObject->GetGrafPtr());
  124.                     BeginUpdate(window);
  125.                     windowObject->DoUpdate(GetWindowPort(window)->visRgn);    // The visRgn contains the region that needs to be updated
  126.                     EndUpdate(window);
  127.                 }
  128.             }
  129.             break;
  130.  
  131.         case activateEvt:
  132.             {
  133.                 WindowRef window = (WindowRef)event->message;
  134.                 CWindow* windowObject = CWindow::GetCWindow(window);
  135.                 if (windowObject != NULL)
  136.                 {
  137.                     windowObject->WindowActivated(event->modifiers & activeFlag);
  138.                 }
  139.             }
  140.             break;
  141.  
  142.         case osEvt:
  143.             if (((event->message >> 24) & 0xFF) == suspendResumeMessage)
  144.             {
  145.                 gApplication->AppActivated((event->message & resumeFlag) != 0);
  146.                 // ??? Do I need to activate/deactivate the frontmost window too?
  147.             }
  148.             break;
  149.  
  150.         default:
  151.             break;
  152.     }
  153.     return false;
  154. }
  155.  
  156.  
  157.  
  158. // --------------------------------------------------------------------
  159. // TApplication
  160. // --------------------------------------------------------------------
  161. // Application constructor
  162.  
  163. TApplication::TApplication(OSType signature) :
  164.     fFinished(false),
  165.     fActive(true),
  166.     fSignature(signature),
  167.     fSleepTime(60)
  168. {
  169.     {
  170.         // First thing to do: set the stack size
  171.         long newLimit = (long)LMGetCurStackBase() - LMGetDefltStack();
  172.  
  173.         // Set the stack size to be at least the default stack size
  174.         if ((long)GetApplLimit() > newLimit)
  175.             SetApplLimit((Ptr)newLimit);
  176.     }
  177.     
  178.     // Remember who you are Rasputine
  179.     assert(gApplication == NULL);                // Can only have on app running
  180.     gApplication = this;
  181.  
  182.     // Voodoo incantation
  183.     MaxApplZone();
  184.  
  185.     MoreMasters();
  186.     MoreMasters();
  187.     
  188.     InitGraf(&qd.thePort);    
  189.     InitFonts();
  190.     InitWindows();
  191.     InitMenus();
  192.     TEInit();
  193.     InitDialogs(NULL);
  194.     InitCursor();                                // Display the arrow cursor
  195.     FlushEvents(everyEvent, 0);                    // Flush all events
  196.  
  197.     // Turn watch cursor on while initing app
  198.     {
  199.         CursHandle curH;
  200.         if (NULL != (curH = GetCursor(watchCursor)))
  201.             SetCursor(*curH);
  202.     }
  203.  
  204.     // Read in the menu bar
  205.     {
  206.         Handle menuBar = GetNewMBar(kMainMenuBar);
  207.         if (menuBar == NULL)
  208.             ExitToShell();
  209.         SetMenuBar(menuBar);
  210.         DisposeHandle(menuBar);
  211.     }
  212.  
  213.     // Set-up the Apple menu
  214.     AppendResMenu(GetMenuHandle(kAppleMenu), 'DRVR');        // Add content of the Apple Menu to this menu
  215. }
  216.  
  217.  
  218.  
  219. // --------------------------------------------------------------------
  220. // ~TApplication
  221. // --------------------------------------------------------------------
  222. // Application destructor
  223.  
  224. TApplication::~TApplication()
  225. {
  226.  
  227. }
  228.  
  229.  
  230.  
  231. // --------------------------------------------------------------------
  232. // Run
  233. // --------------------------------------------------------------------
  234. // Start running the application
  235.  
  236. void TApplication::Run(void)
  237. {
  238.     DrawMenuBar();                        // Draw Mr. Menu Bar.
  239.     
  240.     MenusWillShow();                    // Enable items appropriately
  241.  
  242.     InitCursor();                        // Show the cursor
  243.     
  244.     MainEventLoop();                    // Process incoming events
  245. }
  246.  
  247.  
  248.  
  249. // --------------------------------------------------------------------
  250. // MainEventLoop
  251. // --------------------------------------------------------------------
  252.  
  253. void TApplication::MainEventLoop(void)
  254. {
  255.     while (!fFinished)
  256.     {
  257.         EventRecord event;
  258.  
  259.         if (!WaitNextEvent(everyEvent, &event, fSleepTime, NULL))
  260.             event.what = nullEvent;
  261.         Event(event);
  262.     }
  263. }
  264.  
  265.  
  266.  
  267. // --------------------------------------------------------------------
  268. // Event
  269. // --------------------------------------------------------------------
  270. // Handles an event. Dispatch to a window if appropriate.
  271.  
  272. void TApplication::Event(const EventRecord& event)
  273. {
  274.     {
  275.         // Decides which window is this event targetted at, if any
  276.         CWindow* windowObject;
  277.         if (event.what == updateEvt)
  278.             windowObject = CWindow::GetCWindow((WindowRef) event.message); // (-)
  279.         else
  280.             windowObject = CWindow::GetCWindow(FrontWindow());
  281.         
  282.         if (windowObject != NULL)
  283.         {
  284.             // Let the window filter the event
  285.             TDrawContext drawContext(windowObject->GetGrafPtr());
  286.             if (drawContext.Lock())
  287.             {
  288.                 Boolean eventHandled = windowObject->FilterEvent(event);
  289.                 drawContext.Unlock();
  290.                 if (eventHandled)
  291.                     return;
  292.             }
  293.         }
  294.     }
  295.     
  296.     switch (event.what)
  297.     {
  298.         case nullEvent:
  299.             Pulse();
  300.             break;
  301.         case mouseDown:
  302.             {
  303.                 short part;        // Code indicating where the click occured
  304.                 WindowRef window;
  305.                 CWindow* windowObject;
  306.                 part = FindWindow(event.where, &window);
  307.                 windowObject = CWindow::GetCWindow(window);
  308.                 
  309.                 switch (part)
  310.                 {
  311.                     case inMenuBar:
  312.                         // Call MenusWillShow() BEFORE MenuSelect()
  313.                         MenusWillShow();            // Update the menu items (enable/disable)
  314.                         /*if (window != NULL)
  315.                             window->MenusWillShow();
  316.                         */
  317.                         // Process the command
  318.  
  319.                         HandleMenuCommand(MenuSelect(event.where));                        break;
  320.  
  321.                     case inSysWindow:
  322.                         SystemClick(&event, window);// Click in a "system" window (DA...)
  323.                         break;
  324.  
  325.                     case inContent:
  326.                         {
  327.                             if (windowObject != NULL)
  328.                             {
  329.                                 SetPort(windowObject->GetGrafPtr());
  330.                                 ClipRect(&windowObject->GetGrafPtr()->portRect);    // ??? Use Frame()
  331.                                 windowObject->MouseDown(event);
  332.                             }
  333.                         }
  334.                         break;
  335.  
  336.                     case inDrag:
  337.                         {
  338.                             DragWindow(window, event.where, 
  339.                                     CRect(-32000, -32000, 32000, 32000));
  340.                             if (windowObject != NULL)
  341.                                 windowObject->FrameMoved(
  342.                                         CPoint(*(Point*)&windowObject->
  343.                                             GetGrafPtr()->portRect.left));
  344.                         }
  345.                         break;
  346.  
  347.                     case inGrow:
  348.                         if (windowObject != NULL)
  349.                         {
  350.                             long growSize;
  351.                             // ??? Should use info from the window class
  352.                             CRect limitRect(100, 100, 1000, 1000) ;
  353.                             CRect windowRect;
  354.  
  355.                             growSize = GrowWindow(window, event.where, 
  356.                                                                 limitRect);
  357.  
  358.                             if (growSize != 0)
  359.                                 windowObject->ResizeTo(LowWord(growSize),
  360.                                                      HighWord(growSize));
  361.                         }
  362.                         break;
  363.  
  364.                     case inGoAway:
  365.                         if (windowObject != NULL && 
  366.                                         TrackGoAway(window, event.where))
  367.                         {
  368.                             if (windowObject->CloseRequested())
  369.                                 windowObject->Close();
  370.                         }
  371.                         break;
  372.  
  373.                     case inZoomIn:
  374.                     case inZoomOut:
  375.                         if (windowObject != NULL && 
  376.                                     TrackBox(window, event.where, part))
  377.                         {
  378.                             windowObject->Zoom(part == inZoomOut);
  379.                         }
  380.                         break;
  381.                 }
  382.             }
  383.             break;
  384.  
  385.         case keyDown:
  386.             if (event.modifiers & cmdKey)        // Command key down
  387.             {
  388.                 // Update the menu items (enable/disable)
  389.                 MenusWillShow();                                    
  390.                 // Call MenusWillShow() BEFORE MenuKey()
  391.                 // Process the commands
  392.                 HandleMenuCommand(MenuKey(
  393.                                 (char)(event.message & charCodeMask)));
  394.             }
  395.             break;
  396.  
  397.         case diskEvt:
  398.             {
  399.                 if (event.message >> 16)
  400.                 {
  401.                     Point where = {-1, -1};
  402.                     (void) DIBadMount(where, event.message);
  403.                 }
  404.             };
  405.             break;
  406.  
  407.         case updateEvt:
  408.             {
  409.                 CWindow* windowObject;
  410.                 WindowRef window = (WindowRef)event.message;
  411.                 windowObject = CWindow::GetCWindow(window);
  412.                 if (windowObject != NULL)
  413.                 {
  414.                     SetPort(windowObject->GetGrafPtr());
  415.                     BeginUpdate(window);
  416.                     // The visRgn contains the region that needs to be updated
  417.                     windowObject->DoUpdate(
  418.                             windowObject->GetGrafPtr()->visRgn);
  419.                     EndUpdate(window);
  420.                 }
  421.             }
  422.             break;
  423.  
  424.         case activateEvt:
  425.             {
  426.                 CWindow* windowObject;
  427.                 WindowRef window = (WindowRef)event.message;
  428.                 windowObject = CWindow::GetCWindow(window);
  429.                 if (windowObject != NULL)
  430.                     windowObject->WindowActivated(event.modifiers & 
  431.                                                             activeFlag);
  432.             }
  433.             break;
  434.  
  435.         case osEvt:
  436.             switch ((event.message & osEvtMessageMask) >> 24)
  437.             {
  438.                 case mouseMovedMessage:
  439.                     break;
  440.  
  441.                 case suspendResumeMessage:
  442.                     AppActivated((event.message & resumeFlag) != 0);
  443.                     // ??? Change the sleep time
  444.                     break;
  445.             }
  446.             break;
  447.  
  448.         case kHighLevelEvent:
  449.             (void)AEProcessAppleEvent(&event);
  450.             break;
  451.  
  452.         default:
  453.             break;
  454.     }
  455. }
  456.  
  457.  
  458.  
  459. // --------------------------------------------------------------------
  460. // MenusWillShow
  461. // --------------------------------------------------------------------
  462. // Hook function called before the menus get displayed.
  463. // A chance to enable/disable menus
  464.  
  465. void TApplication::MenusWillShow(void)
  466. {
  467.     CWindow* windowObject = CWindow::GetCWindow(FrontWindow());
  468.     if (windowObject != NULL)
  469.     {
  470.         windowObject->MenusWillShow();
  471.     }
  472. }
  473.  
  474.  
  475.  
  476. // --------------------------------------------------------------------
  477. // Pulse
  478. // --------------------------------------------------------------------
  479. // Idle time...
  480.  
  481. void TApplication::Pulse(void)
  482. {
  483.     for (CWindow* window = CWindow::GetFirstWindow(); 
  484.                         window != NULL; window = window->GetNextWindow())
  485.     {
  486.         window->Pulse();
  487.     }
  488. }
  489.  
  490.  
  491.  
  492. // --------------------------------------------------------------------
  493. // AppActivated
  494. // --------------------------------------------------------------------
  495. // Hook function called when the application is activated or 
  496. // deactivated.
  497.  
  498. void TApplication::AppActivated(Boolean active)
  499. {
  500.     fActive = active;
  501. }
  502.  
  503.  
  504.  
  505. // --------------------------------------------------------------------
  506. // Event
  507. // --------------------------------------------------------------------
  508. // Hook function called when an AppleEvent is received.
  509.  
  510. OSErr TApplication::Event(AppleEvent* messagein, 
  511.                             AppleEvent* reply, 
  512.                             OSType eventID)
  513. {
  514. #pragma unused(messagein)
  515. #pragma unused(reply)
  516.  
  517.     OSErr result = noErr;
  518.  
  519.     switch (eventID)
  520.     {
  521.         case kAEOpenApplication:
  522.             break;
  523.             
  524.         case kAEQuitApplication:
  525.             if (QuitRequested())
  526.             {
  527.                 Quit();
  528.             }
  529.             else
  530.             {
  531.                 result = userCanceledErr;
  532.             }
  533.             break;
  534.             
  535.         case kAEOpenDocuments:
  536.             // Fall in kAEPrintDocuments
  537.         case kAEPrintDocuments:
  538.             // Fall in default case
  539.         default:
  540.             result = errAEEventNotHandled;
  541.     }
  542.     
  543.     return result;
  544. }
  545.  
  546.  
  547.  
  548. // --------------------------------------------------------------------
  549. // HandleAppleEvent
  550. // --------------------------------------------------------------------
  551. // Static allback function called when an Apple Event is received.
  552.  
  553. pascal OSErr TApplication::HandleAppleEvent(AppleEvent* messagein, 
  554.                                                 AppleEvent* reply, 
  555.                                                 OSType eventID)
  556. {
  557.     // This static method is just a dispatcher to a virtual method (Event)
  558.     // that can be overriden by subclasses.
  559.     return gApplication->Event(messagein, reply, eventID);
  560. }
  561.  
  562.  
  563.  
  564. // --------------------------------------------------------------------
  565. // InitAppleEvents
  566. // --------------------------------------------------------------------
  567. // Function called to initialize the Apple Event handlers.
  568.  
  569. void TApplication::InitAppleEvents(void)
  570. {
  571.     /* The following series of calls installs all our AppleEvent Handlers.
  572.     *   These handlers are added to the application event handler list that 
  573.     *   the AppleEvent manager maintains.  So, whenever an AppleEvent happens
  574.     *   and we call AEProcessEvent, the AppleEvent manager will check our
  575.     *   list of handlers and dispatch to it if there is one.
  576.     */
  577.   
  578.     if (fEnvironment.HasAppleEvent()) 
  579.     {
  580.         struct AEinstalls 
  581.         {
  582.             AEEventClass eventClass;
  583.             AEEventID eventID;
  584.         };
  585.         typedef struct AEinstalls AEinstalls;
  586.  
  587.         static AEinstalls handlers[] =  
  588.         {
  589.             /* The four required AppleEvents. */
  590.             { kCoreEventClass, kAEOpenApplication},  
  591.             { kCoreEventClass, kAEOpenDocuments },
  592.             { kCoreEventClass, kAEQuitApplication },
  593.             { kCoreEventClass, kAEPrintDocuments }, 
  594.             
  595.         };
  596.  
  597.         AEEventHandlerUPP upp = NewAEEventHandlerProc(HandleAppleEvent);
  598.         for (int i = 0; i < ((sizeof(handlers) / sizeof(AEinstalls))); i++) 
  599.         {
  600.             (void)AEInstallEventHandler(handlers[i].eventClass,
  601.                                         handlers[i].eventID,
  602.                                            upp, 
  603.                                         handlers[i].eventID, false);
  604.         }
  605.     }
  606. }
  607.  
  608.  
  609.  
  610. // --------------------------------------------------------------------
  611. // HandleMenuCommand
  612. // --------------------------------------------------------------------
  613. // Function dispatching a menu selection to a menu handler.
  614.  
  615. void TApplication::HandleMenuCommand(long menuResult)
  616. {
  617.     short menu = HighWord(menuResult);
  618.     short item = LowWord(menuResult);
  619.  
  620.     MenuCommand(menu, item);
  621.  
  622.     HiliteMenu(0);
  623. }
  624.  
  625.  
  626.  
  627. // --------------------------------------------------------------------
  628. // MenuCommand
  629. // --------------------------------------------------------------------
  630. // Hook function called when a menu selection is made.
  631.  
  632. Boolean TApplication::MenuCommand(short menu, short item)
  633. {
  634.     Boolean result = false;
  635.     
  636.     switch (menu)
  637.     {
  638.         case kAppleMenu:
  639.             {
  640.                 if (item == kAboutMenuItem)
  641.                 {
  642.                     AboutRequested();
  643.                 }
  644.                 else
  645.                 {
  646.                     // Open the desk accessory
  647.                     Str255 itemName;
  648.                     GetMenuItemText(GetMenuHandle(kAboutMenuItem), 
  649.                                                         item, itemName);
  650.                     OpenDeskAcc(itemName);
  651.                 }
  652.                 result = true;
  653.             };
  654.             break;
  655.  
  656.         case kFileMenu:
  657.             {
  658.                 // Items in the File menu are close and quit.
  659.                 if (QuitRequested())
  660.                     Quit();
  661.                 result = true;
  662.             };
  663.             break;
  664.  
  665.         case kEditMenu:
  666.             {
  667.                 // Pass the command on to the Desk Manager
  668.                 if (SystemEdit(item - 1))            
  669.                     result = true;
  670.             }
  671.             break;
  672.     }
  673.  
  674.     return result;
  675. }
  676.  
  677.  
  678.  
  679. // --------------------------------------------------------------------
  680. // AboutRequested
  681. // --------------------------------------------------------------------
  682. // Hook function called to display an about box.
  683.  
  684. void TApplication::AboutRequested(void)
  685. {
  686.     // Display about box
  687.     Alert(kAboutBoxDialog, NULL);            
  688. }
  689.  
  690.  
  691.  
  692. // --------------------------------------------------------------------
  693. // Quit
  694. // --------------------------------------------------------------------
  695. // Hook function called to quit.
  696.  
  697. void TApplication::Quit(void)
  698. {
  699.     assert(!fFinished);
  700.     fFinished = true;
  701. }
  702.  
  703.  
  704.  
  705. // --------------------------------------------------------------------
  706. // QuitRequested
  707. // --------------------------------------------------------------------
  708. // Hook function called when the user ask to quit.
  709. // Returns true if really want to quit, or false to cancel.
  710.  
  711. Boolean TApplication::QuitRequested(void)
  712. {
  713.     return true;
  714. }
  715.  
  716.  
  717.  
  718. // --------------------------------------------------------------------
  719. // GetScrapContent
  720. // --------------------------------------------------------------------
  721.  
  722. unsigned long GetScrapContent(void)
  723. // Returns the content of the scrap (kHasText, kHasPict, etc...)
  724. {
  725.     unsigned long result;
  726.     long byteCount;
  727.     long len;
  728.     long resTypeCount;
  729.     ScrapItemPtr sp;
  730.     char sState;
  731.  
  732.     result = 0;
  733.  
  734.     LoadScrap();                                /* make sure the scrap is in ram */
  735.  
  736.     if ((!LMGetScrapHandle()) ||                /* no scrap handle */
  737.         (LMGetScrapState() <= 0) ||            /* bad scrap state */
  738.         (!LMGetScrapSize()))                    /* nothing in scrap */
  739.     {
  740.         return 0;                                /* nothing to get */
  741.     }
  742.  
  743.     sState = HGetState(LMGetScrapHandle());    /* get current state of scrap */
  744.     HLock(LMGetScrapHandle());                /* lock it down */
  745.  
  746.     sp = (ScrapItemPtr)StripAddress(*LMGetScrapHandle());/* pointer to first item in scrap */
  747.     resTypeCount = 0;                            /* no resources added yet */
  748.     byteCount = 0;                                /* no bytes added yet */
  749.  
  750.     while (byteCount < LMGetScrapSize())
  751.         /* loop over all items in scrap */
  752.         {
  753.             if (sp->scrapType == 'PICT')
  754.                 result |= kScrapHasPict;
  755.             else if (sp->scrapType == 'TEXT')
  756.                 result |= kScrapHasText;
  757.             else if (sp->scrapType == 'snd ')
  758.                 result |= kScrapHasSound;
  759.             else if (sp->scrapType == 'moov')
  760.                 result |= kScrapHasMovie;
  761.  
  762.             len = (sizeof(ScrapItem) - 2 + sp->scrapLength + 1) & ~1;/* no. bytes used up by this resource (word aligned) */
  763.             sp = (ScrapItemPtr)((long)sp + len);/* update pointer to next resource */
  764.             byteCount += len;                    /* count no. bytes processed so far */
  765.             resTypeCount++;                        /* another resource added */
  766.         }
  767.  
  768.     HSetState(LMGetScrapHandle(), sState);    /* restore state of scrap */
  769.  
  770.     return result;
  771. }
  772.